package controllers;

import com.avaje.ebean.Ebean;
import models.User;
import org.codehaus.jackson.JsonNode;
import org.hibernate.validator.constraints.Range;
import org.json.JSONObject;
import org.json.XML;
import play.data.Form;
import play.data.validation.Constraints;
import play.mvc.Content;
import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.Security;
import scala.Tuple2;
import scala.collection.Seq;
import utils.ContainGame;
import utils.UrlReader;
import validators.YoutubeAdress;
import views.html.*;

import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.xml.parsers.*;
import java.io.File;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;

import models.*;

import org.w3c.dom.*;
import views.html.helper.checkbox;
import views.html.helper.options;

import static play.data.Form.form;


/**
 * Created with IntelliJ IDEA.
 * User: David
 * Date: 28.02.13
 * Time: 15:06
 * To change this template use File | Settings | File Templates.
 */
@Security.Authenticated(Secured.class)
public class Kiry extends Controller {

    public static class AddNewGame {

        @Constraints.Required
        public String gameTitle;

        public long idGameDb;

        @YoutubeAdress
        public String youtube;

        @Constraints.Required
        @Range(min = 0, max = 100)
        public short rating;

        @Temporal(TemporalType.DATE)
        public Date releaseDate_submit;

        @Constraints.Required
        public String platform;

        public List<Genre> genres = new ArrayList<>();

        public Compagny publisher;

        public Compagny developer;

        public String validate() {
            try {
                Long.parseLong(platform);
            } catch (Exception e) {
                return e.getMessage();
            }
           return null;
        }
    }

    public static Result index(int list) {
        List<? extends ContainGame> gamesToShow;
        String email = session("email");
        switch (list) {
            case 1: // wish game
                gamesToShow =  UserWishGame.findUserGames(email);
                break;
            case 2: // own game
                gamesToShow =  UserOwnGame.findUserGames(email);
                break;
            case 4: // all games
                gamesToShow = Game.findAll();
                break;
            default:
            case 0: // default view : game without state
                gamesToShow =  Game.findGameWithoutState(email);
        }

        return ok(index.render(gamesToShow, User.findByEmail(email), list));
    }

    public static Result welcome() {
        return ok(welcome.render(User.findByEmail(session("email"))));
    }

    public static Result newgame() {
        // TODO : DELETE!
        importPlatform();
        return ok(newgame.render(form(AddNewGame.class), getPlatformOptions()));
    }

    public static Result addNewGame() {
        Form<AddNewGame> addNewGame = form(AddNewGame.class).bindFromRequest();
        if (addNewGame.hasErrors()) {
            return badRequest(newgame.render(addNewGame, getPlatformOptions()));
        } else {
            Game game = new Game(addNewGame.get().gameTitle);
            game.idgamedb = addNewGame.get().idGameDb;
            game.rating = addNewGame.get().rating;
            game.youtube = addNewGame.get().youtube;
            game.releasedate = addNewGame.get().releaseDate_submit;
            game.platform = Platform.findByIdGameDb(Long.parseLong(addNewGame.get().platform));
            game.genres = addNewGame.get().genres;
            for (Genre g : game.genres)
                g.save();
            game.publisher = addNewGame.get().publisher;
            game.publisher.save();
            game.developer = addNewGame.get().developer;
            game.developer.save();
            game.account_email = session("email");
            game.save();
            flash("success", "Le jeu a été ajouté avec succès.");
            return redirect(routes.Kiry.index(0));
        }
    }

    private static Seq<Tuple2<String, String>> getPlatformOptions() {
        Map<String, String> m = new HashMap<>();
        for (Platform p : Platform.findAll())
           m.put(String.valueOf(p.idgamedb), p.name);
        return views.html.helper.options.apply(m);
    }

    public static Result addWishGame(String email, long game) {
        if (!email.equals(session("email")))
            flash("error", "Vous n'avez pas l'autorisation d'effectuer cette action.");
        else
            try {
                UserWishGame uwg = new UserWishGame(new UserWishGame.UserWishGameKeys(email, game), (short)0);
                uwg.save();
            } catch (Exception e) {
                flash("error", "Ce jeu est déjà dans votre liste de souhaits.");
            }
        return redirect(routes.Kiry.index(0));
    }

    public static Result addOwnGame(String email, long game) {
        if (!email.equals(session("email")))
            flash("error", "Vous n'avez pas l'autorisation d'effectuer cette action.");
        else
            try {
                UserOwnGame uog = new UserOwnGame(new UserOwnGame.UserOwnGameKeys(email, game));
                uog.save();
            } catch (Exception e) {
                flash("error", "Vous possédez déjà ce jeu.");
            }
        return redirect(routes.Kiry.index(0));
    }

    public static Result removeWishGame(String email, long game) {
        if (!email.equals(session("email")))
            flash("error", "Vous n'avez pas l'autorisation d'effectuer cette action.");
        else
            try {
                UserWishGame.removeWishGame(email, game);
            } catch (Exception e) {
                flash("error", "Un problème est survenu lors de la suppression du jeu de la liste de souhait.");
            }
        return redirect(routes.Kiry.index(0));
    }

    public static Result getGameList(String search) {
        try {
            search = URLEncoder.encode(search, "UTF-8");
            String content = UrlReader.read("http://thegamesdb.net/api/GetGamesList.php?name=" + search);
            return ok(content);
        } catch (Exception e) {
            return ok();
        }
    }

    public static Result getGameInfo(String game) {
        try {
            long id = Long.parseLong(game);
            String content = UrlReader.read("http://thegamesdb.net/api/GetGame.php?id=" + id);
            return ok(content);
        } catch (Exception e) {
            return ok();
        }
    }

    public static Result importPlatform() {
        try {
            String content = UrlReader.read("http://thegamesdb.net/api/GetPlatformsList.php");
            DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
                    .newInstance();
            DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
            Document document = docBuilder.parse("http://thegamesdb.net/api/GetPlatformsList.php");
            Platform.deleteAll();
            importDocument(document.getDocumentElement());
            flash("success", "La liste des consoles a été mise à jour!");
            return redirect(routes.Kiry.index(0));
        } catch (Exception e) {
            flash("error", "Un problème est survenu lors de la mise à jour des consoles.");
            return redirect(routes.Kiry.index(0));
        }
    }

    private static void importDocument(Node node) {
        NodeList nodeList = node.getChildNodes();
        if (node.getNodeName().equals("Platform")) {
            String name = "undefined";
            long id = -1;
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node currentNode = nodeList.item(i);
                if (currentNode.getNodeName().equals("id"))
                    id = Long.parseLong(currentNode.getTextContent());
                if (currentNode.getNodeName().equals("name"))
                    name =  currentNode.getTextContent();
            }
            Platform p = new Platform(name);
            p.idgamedb = id;
            p.save();
        } else {
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node currentNode = nodeList.item(i);
                if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
                    importDocument(currentNode);
                }
            }
        }
    }

    public static Result getGenresList() {
        return ok(listToString(Genre.getStringList()));
    }

    public static Result getCompagniesList() {
        return ok(listToString(Compagny.getStringList()));
    }

    public static Result getDetailsGame(Long game) {
        return ok(detailsgame.render(Game.findById(game), User.findByEmail(session("email"))));
    }

    private static String listToString(List<String> list) {
        String l = "[";
        for (String s : list)
            l += "\"" + s + "\",";
        return l.substring(0, l.length()-1)+"]";
    }
}
